package org.abc.fund.service.factorService;

import org.abc.fund.entity.factorEntity.DataSourceIngestionHistory;
import org.abc.fund.entity.factorEntity.NavData;
import org.abc.fund.repository.factorRepository.DataSourceIngestionHistoryRepository;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 数据源采集类
 */
@Service
public class DataSourceIngestionHistoryService {
    
    @Autowired
    private DataSourceIngestionHistoryRepository historyRepository;
    private final RestTemplate restTemplate = new RestTemplate();
    //@Autowired
    //private DataSourceConfigRepository dataSourceConfigRepository;
    @Autowired
    private FactorAlgorithm factorAlgorithm;
    @Value("${tianfu.api.real-time-url:https://fundgz.1234567.com.cn/js/{fundCode}.js}")
    private String realTimeUrl;
    List<NavData> navDataList = new ArrayList<>();
    @Value("${tianfu.api.history-url:https://fundf10.eastmoney.com/F10DataApi.aspx?type=lsjz&code={code}&page={page}&sdate={start_date}&edate={end_date}&per={per}}")
    private String historyUrl;

    /**
     * 保存采集历史记录
     */
    public DataSourceIngestionHistory saveHistory(DataSourceIngestionHistory history) {
        return historyRepository.save(history);
    }
    public List<Double> getShowData(String fundCode, String start, String end) {
        LocalDate startDate = LocalDate.parse(start);
        LocalDate endDate   = LocalDate.parse(end);
        long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);
        int size = (int) ((daysBetween+29)/30);
        List<Double> returnData = new ArrayList<>();
        List<NavData> navDataList;
        for (int page = 1; page <= size; page++) {
            try {

                String url = historyUrl
                        .replace("{code}", fundCode)
                        .replace("{page}", String.valueOf(page))
                        .replace("{start_date}", start)
                        .replace("{end_date}", end)
                        .replace("{per}", "30");
                System.out.println("获取基金 " + fundCode + " 历史数据, 第 " + page + " 页");
                HttpHeaders headers = new HttpHeaders();
                headers.set("User-Agent", "Mozilla/5.0 …");
                HttpEntity<String> entity = new HttpEntity<>(headers);
                ResponseEntity<String> response =
                        restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
                String responseBody = response.getBody();
                if (responseBody != null) {
                    navDataList=parseAndSaveData(fundCode, responseBody);
                    double simpleReturn = factorAlgorithm.calculateSimpleReturn(navDataList);
                    double calculateAnnualizedReturn= factorAlgorithm.calculateAnnualizedReturn(navDataList);
                    double calculateLogReturn= factorAlgorithm.calculateLogReturn(navDataList);
                    double calculateVolatility= factorAlgorithm.calculateVolatility(navDataList);
                    double sharpeRatio;
                    try {
                        sharpeRatio = factorAlgorithm.calculateSharpeRatio(navDataList,
                                factorAlgorithm.fetchRfDaily(start, end));
                    } catch (Exception ex) {
                        sharpeRatio = factorAlgorithm.calculateSharpeRatio(navDataList, 1.0);
                    }
                    double calculateMaxDrawdown=factorAlgorithm.calculateMaxDrawdown(navDataList);
                    double calculateDownsideRisk=factorAlgorithm.calculateDownsideRisk(navDataList,0.001);
                    double calculateRSI=factorAlgorithm.calculateRSI(navDataList);
                    double PurchaseOpenFrequencyFactor=factorAlgorithm.calculateRedemptionStatusFactor(navDataList).get(0);
                    double RedemptionOpenFrequencyFactor=factorAlgorithm.calculateRedemptionStatusFactor(navDataList).get(1);
                    double calculateMovingAverage=factorAlgorithm.calculateMovingAverage(navDataList,daysBetween);
                    returnData.add(simpleReturn);
                    returnData.add(calculateAnnualizedReturn);
                    returnData.add(calculateLogReturn);
                    returnData.add(calculateVolatility);
                    returnData.add(sharpeRatio);
                    returnData.add(calculateMaxDrawdown);
                    returnData.add(calculateDownsideRisk);
                    returnData.add(calculateRSI);
                    returnData.add(PurchaseOpenFrequencyFactor);
                    returnData.add(RedemptionOpenFrequencyFactor);
                    returnData.add(calculateMovingAverage);
                }
            } catch (Exception e) {
                System.err.println("基金 " + fundCode + " 第 " + page + " 页获取失败: " + e.getMessage());
            }
        }
        return returnData;
    }
    public List<NavData> getJJData(String fundCode, String start, String end) {
        LocalDate startDate = LocalDate.parse(start);
        LocalDate endDate   = LocalDate.parse(end);
        long daysBetween = ChronoUnit.DAYS.between(startDate, endDate);
        int size = (int) ((daysBetween+29)/30);
        List<NavData> navDataList = new ArrayList<>();
        for (int page = 1; page <= size; page++) {
            try {

                String url = historyUrl
                        .replace("{code}", fundCode)
                        .replace("{page}", String.valueOf(page))
                        .replace("{start_date}", start)
                        .replace("{end_date}", end)
                        .replace("{per}", "30");
                System.out.println("获取基金 " + fundCode + " 历史数据, 第 " + page + " 页");
                HttpHeaders headers = new HttpHeaders();
                headers.set("User-Agent", "Mozilla/5.0 …");
                HttpEntity<String> entity = new HttpEntity<>(headers);
                ResponseEntity<String> response =
                        restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
                String responseBody = response.getBody();
                if (responseBody != null) {
                    navDataList=parseAndSaveData(fundCode, responseBody);
                }
            } catch (Exception e) {
                System.err.println("基金 " + fundCode + " 第 " + page + " 页获取失败: " + e.getMessage());
            }
        }
        return navDataList;
    }
    /**
     * 用 Jsoup 从 content:"…"<tr>…</tr> 部分解析出每行 td 纯文本，并填充到 navDataList
     */
    public List<NavData> parseAndSaveData(String fundCode, String responseBody) {
        // 先用正则抽取 content:"…"
        List<NavData> returnData = new ArrayList<>();
        Pattern tablePattern = Pattern.compile("content:\"([^\"]+)\"");
        Matcher tableMatcher = tablePattern.matcher(responseBody);
        if (!tableMatcher.find()) {
            System.err.println("未找到 content 字段");
            return null;
        }
        String tableHtml = tableMatcher.group(1);
        // 由于 content 里的 <tr>…</tr> 可能是片段，补全成完整HTML
        String html = "<table>" + tableHtml + "</table>";
        Document doc = Jsoup.parse(html);
        Elements rows = doc.select("tr");

        for (Element row : rows) {
            Elements cells = row.select("td");
            // 根据货币/股票基金列数可能不同，至少要有6列才能解析
            if (cells.size() < 6) continue;

            String dateStr   = cells.get(0).text().replace("*", "").trim();
            String unitStr   = cells.get(1).text().trim();
            String cumuStr   = cells.get(2).text().trim();
            String dailyStr  = cells.get(3).text().replace("%", "").trim();
            String subStatus = cells.get(4).text().trim();
            String redStatus = cells.get(5).text().trim();
            String diviInfo  = cells.size() > 6 ? cells.get(6).text().trim() : "";

            LocalDate    netDate = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            double       unitVal = Double.parseDouble(unitStr);
            double       cumuVal = Double.parseDouble(cumuStr);
            double       daily   = dailyStr.isEmpty() ? 0.0 : Double.parseDouble(dailyStr);

            NavData nav = new NavData(
                    netDate, unitVal, cumuVal, daily,
                    subStatus, redStatus, diviInfo
            );
            returnData.add(nav);

            System.out.printf("解析: %s | %s | %s%% | %s / %s / %s%n",
                    dateStr, unitStr, dailyStr, subStatus, redStatus, diviInfo
            );
            // TODO: 如果需要立即保存到数据库，也可以在这里调用 save 方法
        }
        return returnData;
    }
    private Double convertToDouble(String valueStr) {
        try {
            return Double.parseDouble(valueStr);
        } catch (NumberFormatException e) {
            // 如果转换失败，返回 null 或默认值
            return null;
        }
    }

    private LocalDate convertToLocalDate(String dateStr) {
        try {
            // 假设日期格式为 "yyyy-MM-dd"
            return LocalDate.parse(dateStr);
        } catch (Exception e) {
            // 如果日期格式不匹配，可以使用 DateTimeFormatter 指定格式
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            return LocalDate.parse(dateStr, formatter);
        }
    }


    
    /**
     * 更新采集历史记录状态
     */
    public DataSourceIngestionHistory updateHistoryStatus(Long historyId, DataSourceIngestionHistory.IngestionStatus status, Integer ingestedCount, String errorMessage) {
        DataSourceIngestionHistory history = historyRepository.findById(historyId)
                .orElseThrow(() -> new RuntimeException("采集历史记录不存在: " + historyId));
        
        history.setStatus(status);
        history.setRecordCount(ingestedCount);
        history.setErrorMessage(errorMessage);
        history.setEndTime(LocalDateTime.now());
        history.calculateDuration();
        
        return historyRepository.save(history);
    }
    
    /**
     * 根据数据源ID获取采集历史
     */
    public List<Map<String, Object>> getDataSourceHistory(Long dataSourceId) {
        List<DataSourceIngestionHistory> histories = historyRepository.findByDataSourceIdOrderByStartTimeDesc(dataSourceId);
        return convertToMapList(histories);
    }
    
    /**
     * 根据数据源ID分页获取采集历史
     */
    public Page<Map<String, Object>> getDataSourceHistoryPage(Long dataSourceId, int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        Page<DataSourceIngestionHistory> historyPage = historyRepository.findByDataSourceIdOrderByStartTimeDesc(dataSourceId, pageable);
        return historyPage.map(this::convertToMap);
    }
    
    /**
     * 根据数据源ID和时间范围获取采集历史
     */
    public List<Map<String, Object>> getDataSourceHistoryByTimeRange(Long dataSourceId, LocalDateTime startTime, LocalDateTime endTime) {
        List<DataSourceIngestionHistory> histories = historyRepository.findByDataSourceIdAndTimeRange(dataSourceId, startTime, endTime);
        return convertToMapList(histories);
    }
    
    /**
     * 获取数据源采集统计信息
     */
    public Map<String, Object> getDataSourceStatistics(Long dataSourceId) {
        Object[] stats = historyRepository.getIngestionStatisticsByDataSourceId(dataSourceId);
        
        Map<String, Object> result = new HashMap<>();
        if (stats != null && stats.length >= 5) {
            result.put("totalCount", stats[0]);
            result.put("successCount", stats[1]);
            result.put("failedCount", stats[2]);
            result.put("avgDuration", stats[3]);
            result.put("lastIngestionTime", stats[4]);
            
            // 计算成功率
            Long totalCount = (Long) stats[0];
            Long successCount = (Long) stats[1];
            if (totalCount > 0) {
                result.put("successRate", String.format("%.2f%%", (double) successCount / totalCount * 100));
            } else {
                result.put("successRate", "0.00%");
            }
        } else {
            result.put("totalCount", 0L);
            result.put("successCount", 0L);
            result.put("failedCount", 0L);
            result.put("avgDuration", 0.0);
            result.put("lastIngestionTime", null);
            result.put("successRate", "0.00%");
        }
        
        return result;
    }
    
    /**
     * 获取所有数据源的采集统计信息
     */
    public List<Map<String, Object>> getAllDataSourceStatistics() {
        List<Object[]> statsList = historyRepository.getIngestionStatistics();
        return statsList.stream().map(stats -> {
            Map<String, Object> result = new HashMap<>();
            result.put("dataSourceId", stats[0]);
            result.put("dataSourceName", stats[1]);
            result.put("totalCount", stats[2]);
            result.put("successCount", stats[3]);
            result.put("failedCount", stats[4]);
            result.put("lastIngestionTime", stats[5]);
            
            // 计算成功率
            Long totalCount = (Long) stats[2];
            Long successCount = (Long) stats[3];
            if (totalCount > 0) {
                result.put("successRate", String.format("%.2f%%", (double) successCount / totalCount * 100));
            } else {
                result.put("successRate", "0.00%");
            }
            
            return result;
        }).collect(Collectors.toList());
    }
    
    /**
     * 获取正在执行的采集任务
     */
    public List<Map<String, Object>> getRunningIngestions() {
        List<DataSourceIngestionHistory> runningHistories = historyRepository.findByStatus(DataSourceIngestionHistory.IngestionStatus.RUNNING);
        return convertToMapList(runningHistories);
    }
    
    /**
     * 取消正在执行的采集任务
     */
    public boolean cancelRunningIngestion(Long historyId) {
        DataSourceIngestionHistory history = historyRepository.findById(historyId)
                .orElse(null);
        
        if (history != null && history.getStatus() == DataSourceIngestionHistory.IngestionStatus.RUNNING) {
            history.setStatus(DataSourceIngestionHistory.IngestionStatus.CANCELLED);
            history.setEndTime(LocalDateTime.now());
            history.calculateDuration();
            historyRepository.save(history);
            return true;
        }
        
        return false;
    }
    
    /**
     * 清理历史记录
     */
    public void cleanupHistoryRecords(LocalDateTime beforeTime) {
        historyRepository.deleteByStartTimeBefore(beforeTime);
    }
    
    /**
     * 删除指定数据源的所有历史记录
     */
    public void deleteDataSourceHistory(Long dataSourceId) {
        historyRepository.deleteByDataSourceId(dataSourceId);
    }
    
    /**
     * 将实体对象转换为Map
     */
    private Map<String, Object> convertToMap(DataSourceIngestionHistory history) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", history.getId());
        map.put("dataSourceId", history.getDataSourceId());
        map.put("dataSourceName", history.getDataSourceName());
        map.put("recordCount", history.getRecordCount());
        map.put("ingestedCount", history.getIngestedCount());
        map.put("startTime", formatDateTime(history.getStartTime()));
        map.put("endTime", formatDateTime(history.getEndTime()));
        map.put("status", history.getStatus().name());
        map.put("statusDescription", history.getStatus().getDescription());
        map.put("duration", formatDuration(history.getDuration()));
        map.put("errorMessage", history.getErrorMessage());
        map.put("ingestionType", history.getIngestionType().name());
        map.put("ingestionTypeDescription", history.getIngestionType().getDescription());
        map.put("scriptName", history.getScriptName());
        map.put("parameters", history.getParameters());
        map.put("createTime", formatDateTime(history.getCreateTime()));
        map.put("createdBy", history.getCreatedBy());
        return map;
    }
    
    /**
     * 将实体列表转换为Map列表
     */
    private List<Map<String, Object>> convertToMapList(List<DataSourceIngestionHistory> histories) {
        return histories.stream().map(this::convertToMap).collect(Collectors.toList());
    }
    
    /**
     * 格式化日期时间
     */
    private String formatDateTime(LocalDateTime dateTime) {
        if (dateTime == null) return null;
        return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    }
    
    /**
     * 格式化时长
     */
    private String formatDuration(Long duration) {
        if (duration == null) return null;
        long seconds = duration / 1000;
        long minutes = seconds / 60;
        seconds = seconds % 60;
        return String.format("%02d:%02d", minutes, seconds);
    }
} 